import sys
import os
import pandas as pd
import numpy as np
from loguru import logger
import datetime
import hashlib

# region 原先的导包方式
# 把项目根目录加入 sys.path
# project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))
# sys.path.insert(0, project_root)
# logger.info(f"项目根目录: {project_root}")
# logger.info(f"Python路径: {sys.path[:3]}")
#
# try:
#     from read_data import get_flow_report, get_flow_report_with_fuzzy_rename
#     logger.info("成功导入read_data模块")
# except ImportError as e:
#     logger.error(f"导入read_data模块失败: {e}")
    # 尝试直接导入
# endregion

from App.read_data import get_flow_report, get_flow_report_with_fuzzy_rename



def remove_duplicate_rows(df, window_size=5):
    """
    删除与上一步长所有数据都一样的行（除了时间戳）
    
    Args:
        df (pd.DataFrame): 输入数据框
        window_size (int): 滑动窗口大小，默认为5
    
    Returns:
        pd.DataFrame: 去重后的数据框
    """
    if df.empty or len(df) < window_size:
        return df
    
    # 创建副本避免修改原始数据
    df_cleaned = df.copy()
    
    # 记录原始行数
    original_count = len(df_cleaned)
    
    # 排除时间戳列，只对数值列进行去重处理
    numeric_cols = df_cleaned.select_dtypes(include=[np.number]).columns.tolist()
    
    # 如果时间戳列是datetime类型，需要排除
    datetime_cols = df_cleaned.select_dtypes(include=['datetime64']).columns.tolist()
    for col in datetime_cols:
        if col in numeric_cols:
            numeric_cols.remove(col)
    
    if len(numeric_cols) == 0:
        logger.warning("没有找到数值列，跳过去重处理")
        return df_cleaned
    
    # 创建标记数组，标记需要删除的行
    rows_to_drop = []
    
    for i in range(window_size, len(df_cleaned)):
        # 检查当前行是否与前面连续window_size行都相同
        current_values = df_cleaned.iloc[i][numeric_cols].values.astype(float)
        
        # 检查前面连续window_size行是否都与当前行相同
        all_same = True
        for j in range(1, window_size + 1):
            previous_values = df_cleaned.iloc[i-j][numeric_cols].values.astype(float)
            if not np.allclose(current_values, previous_values, rtol=1e-10, atol=1e-10):
                all_same = False
                break
        
        if all_same:
            rows_to_drop.append(i)
    
    # 删除标记的行
    if rows_to_drop:
        df_cleaned = df_cleaned.drop(df_cleaned.index[rows_to_drop])
        logger.info(f"去重处理完成：删除了 {len(rows_to_drop)} 行重复数据，从 {original_count} 行减少到 {len(df_cleaned)} 行")
    else:
        logger.info("未发现需要删除的重复行")
    
    return df_cleaned


# 定义输出目录
SCRIPT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
BASE_DIR = os.path.join(SCRIPT_DIR, "System_of_C")
DATA_DIR = os.path.join(BASE_DIR, "read_and_process_data")
OUTPUT_DIR = os.path.join(DATA_DIR, "Load_and_devicedata")

# 确保输出目录存在
os.makedirs(OUTPUT_DIR, exist_ok=True)

midu_water = 1000 # 水的密度为1000kg/m3
c_water = 4.186 # 水的比热容为4.186kJ/(kg·℃)
midu_air = 1.204 # 空气的密度为1.204kg/m3
c_air = 1.005 # 空气的比热容为1.005kJ/(kg·℃)
# 计算湿球温度
def calc_wet_bulb_temperature(T, RH):
    # T: 干球温度(℃)，RH: 相对湿度(%)，返回湿球温度(℃)
    Tw = (
        T * np.arctan(0.151977 * (RH + 8.313659) ** 0.5)
        + np.arctan(T + RH)
        - np.arctan(RH - 1.676331)
        + 0.00391838 * RH ** 1.5 * np.arctan(0.023101 * RH)
        - 4.686035
    )
    return Tw
def calc_air_enthalpy_by_t_rh(t, rh, p=101.325):
    """
    t: 干球温度(℃)
    rh: 相对湿度(%)，如50表示50%
    p: 大气压(kPa)
    返回: 焓值(kJ/kg)
    """
    rh = rh / 100  # 转为0~1
    # 饱和水汽压（kPa）
    p_ws = 6.112 * np.exp(17.67 * t / (t + 243.5)) * 0.1
    # 实际水汽分压力
    p_w = rh * p_ws
    # 绝对湿度
    d = 0.622 * p_w / (p - p_w)
    # 焓值
    h = 1.006 * t + d * (2501 + 1.805 * t)
    return h

# 计算主机房环境系统的冷水机组的数据
def read_data_for_device_RefriCycle(start_time, end_time,id):
    """读取并处理主机房冷水机组（主机1）数据
    
    该函数实现如下功能：
        1. 通过get_flow_report获取主机1的原始数据，字段重命名为标准列名
        2. 对各项传感器数据进行合理范围筛选，去除异常值
        3. 计算湿球温度（t_w_wet），并根据能量平衡公式计算冷负荷（load）
        4. 保存原始数据到csv（load_data_RefriCycle_1_raw.csv）
        5. 整理为建模所需的字段：['timestamp', 'load', 'power', 't_w_wet', 't_LD_out','function']
        6. 仅保留主机运行状态为1的数据，去除缺失值和inf异常值
        7. 保存最终可用于建模的数据到csv（load_data_RefriCycle_1.csv）
    
    Args:
        start_time (str): 数据起始时间，格式如 '2025-06-01 00:00:00'
        end_time (str): 数据结束时间，格式如 '2025-06-30 01:00:00'
        id (int): 流报表id接口
    
    Returns:
        pd.DataFrame: 主机1的处理后数据，包含['timestamp', 'load', 'power', 't_w_wet', 't_LD_out', 'function']字段
    
    Raises:
        ValueError: 当数据获取或处理过程中出现问题时
    """

    #id = 36

    # 使用模糊匹配模式，支持不同数字的冷冻机
    pattern_map = {
        r'冷冻机热量表\d+-回水温度': 't_LD_in',  # 冷冻水回水温度
        r'冷冻机\d+-蒸发器出水温度.*': 't_LD_out',  # 冷冻水出水温度
        r'冷冻机\d+-冷凝器回水温度.*': 't_LQ_in',  # 冷却水回水温度
        r'冷冻机热量表\d+-累计流量': 'flow_LD',  # 冷冻水流量
        r'冷冻机热量表\d+-总冷热量': 'load',  # 冷水主机的制冷量
        r'冷冻机电表\d+-功率.*': 'power',  # 压缩机功率
    }
    
    # 精确匹配的映射（用于时间等固定字段）
    exact_rename_map = {
        "时间": "timestamp"
    }
    
    # 使用新的模糊搜索函数获取数据
    data_RefriCycle_2 = get_flow_report_with_fuzzy_rename(
        id=id, 
        start_time=start_time, 
        end_time=end_time, 
        pattern_map=pattern_map,
        exact_rename_map=exact_rename_map
    )
    # 将负荷进行处理 - 计算能量值 (kWh)
    # 使用pandas的时间差计算，避免datetime模块的直接调用
    time_diff = pd.to_datetime(data_RefriCycle_2['timestamp']).diff().dt.total_seconds() 
    data_RefriCycle_2['load'] = data_RefriCycle_2['load']  *3600/ time_diff
    data_RefriCycle_2['flow_LD'] = data_RefriCycle_2['flow_LD'] / time_diff
    # 将10min间隔的数据进行均值，转换为30min间隔的数据
    # 确保timestamp列为datetime类型
    if isinstance(data_RefriCycle_2['timestamp'].iloc[0], str):
        data_RefriCycle_2['timestamp'] = pd.to_datetime(data_RefriCycle_2['timestamp'])
    
    # 只对数值列进行重采样，排除非数值列（如function列可能是字符串）
    numeric_columns = data_RefriCycle_2.select_dtypes(include=[np.number]).columns.tolist()
    non_numeric_columns = data_RefriCycle_2.select_dtypes(exclude=[np.number]).columns.tolist()
    
    # 设置timestamp为索引
    data_RefriCycle_2.set_index('timestamp', inplace=True)
    
    # 分别处理数值列和非数值列
    if len(numeric_columns) > 0:
        # 对数值列进行重采样（均值）
        numeric_data = data_RefriCycle_2[numeric_columns].resample('10min').mean()
    else:
        numeric_data = pd.DataFrame()
    
    if len(non_numeric_columns) > 0:
        # 对非数值列进行重采样（取第一个值）
        # 注意：timestamp现在是索引，所以要从non_numeric_columns中排除
        non_numeric_cols_for_resample = [col for col in non_numeric_columns if col != 'timestamp']
        if non_numeric_cols_for_resample:
            non_numeric_data = data_RefriCycle_2[non_numeric_cols_for_resample].resample('10min').first()
        else:
            non_numeric_data = pd.DataFrame()
    else:
        non_numeric_data = pd.DataFrame()
    
    # 合并数值列和非数值列
    if not numeric_data.empty and not non_numeric_data.empty:
        data_RefriCycle_2 = pd.concat([numeric_data, non_numeric_data], axis=1)
    elif not numeric_data.empty:
        data_RefriCycle_2 = numeric_data
    elif not non_numeric_data.empty:
        data_RefriCycle_2 = non_numeric_data
    else:
        # 如果没有数据，创建一个空的DataFrame
        data_RefriCycle_2 = pd.DataFrame()
    
    # 重置索引，将timestamp重新变为列
    data_RefriCycle_2.reset_index(inplace=True)
    
    logger.info(f"数据重采样完成：从10分钟间隔转换为30分钟间隔，数据点数量从原始数据减少到 {len(data_RefriCycle_2)} 个")
    

    # 去除重复行
    # 对数据进行筛选
    data_RefriCycle_2 = data_RefriCycle_2[
        (data_RefriCycle_2['t_LD_in'] >= 0) & (data_RefriCycle_2['t_LD_in'] <= 40) &
        (data_RefriCycle_2['t_LD_out'] >= 0) & (data_RefriCycle_2['t_LD_out'] <= 40) &
    #    (data_RefriCycle_1['t_w'] >= -100) & (data_RefriCycle_1['t_w'] <= 70) &
    #    (data_RefriCycle_1['d_w'] >= 0) & (data_RefriCycle_1['d_w'] <= 100) &
        (data_RefriCycle_2['flow_LD'] > 1) & (data_RefriCycle_2['flow_LD'] <= 500) &
        (data_RefriCycle_2['power'] >= 1) 

    ]
    # 去除重复行
    logger.info("开始对冷水机组数据进行去重处理...")
    data_RefriCycle_2 = remove_duplicate_rows(data_RefriCycle_2, window_size=2)    
    # 求湿球温度
    #data_RefriCycle_1['t_w'] = data_RefriCycle_1['t_w'] -2
    #data_RefriCycle_1['t_w_wet'] = calc_wet_bulb_temperature(data_RefriCycle_1['t_w'], data_RefriCycle_1['d_w'])
    #data_RefriCycle_1['load'] = data_RefriCycle_1['flow_LD']*midu_water*\
    #        c_water*(data_RefriCycle_1['t_LD_in']-data_RefriCycle_1['t_LD_out'])/3600  # kJ
    data_RefriCycle_2.to_csv(os.path.join(OUTPUT_DIR, "load_data_RefriCycle_1_raw.csv"), index=False)
    
    # 整理数据
    data_RefriCycle_2 = data_RefriCycle_2[['timestamp', 'load', 'power', 't_LQ_in', 't_LD_out']]

    # 只保留运行状态为1的数据
    data_RefriCycle_2 = data_RefriCycle_2[data_RefriCycle_2['power'] >= 1]
    # 去掉缺失值和异常值inf
    data_RefriCycle_2 = data_RefriCycle_2.dropna()
    numeric_cols = data_RefriCycle_2.select_dtypes(include=[np.number]).columns
    if len(numeric_cols) > 0:
        data_RefriCycle_2 = data_RefriCycle_2[~np.isinf(data_RefriCycle_2[numeric_cols]).any(axis=1)]
    # 筛选出功率大于0的数据
    data_RefriCycle_2 = data_RefriCycle_2[data_RefriCycle_2['load'] > 0]
    data_RefriCycle_2 = data_RefriCycle_2[data_RefriCycle_2['t_LQ_in'] > data_RefriCycle_2['t_LD_out']]

    data_RefriCycle_2.to_csv(os.path.join(OUTPUT_DIR, "load_data_RefriCycle_1.csv"), index=False)

    return data_RefriCycle_2


def allocate_flow_to_pumps_universal(row, pump_count=4, min_frequency=10):
    """
    通用流量分配算法：根据各泵运行状态和频率分配总流量
    
    该函数根据水泵的运行状态和频率，按比例将总流量分配给各个水泵。
    分配原则：
    1. 只有运行状态>0且频率>min_frequency的水泵才参与流量分配
    2. 流量分配比例 = 该泵频率 / 所有运行泵频率之和
    3. 如果所有泵都不运行，则各泵流量为0
    
    Args:
        row (pd.Series): 包含各泵频率、运行状态和总流量的数据行
        pump_count (int): 水泵数量，默认4
        min_frequency (float): 最小有效频率，默认10
    
    Returns:
        list: 各泵分配的流量列表
        
    Author: zq
    Date: 2025.01.08 17:35:00
    Version: 2.0
    """
    total_flow = row['flow_total']
    
    # 获取各泵的运行状态和频率
    pump_info = []
    for pump_id in range(1, pump_count + 1):
        function = row.get(f'function_pump{pump_id}', 0)
        frequency = row.get(f'frequency_pump{pump_id}', 0)
        
        # 只有运行状态>0且频率>min_frequency的泵才参与分配
        if function > 0 and frequency > min_frequency:
            pump_info.append((pump_id - 1, frequency))  # 使用0-based索引
    
    # 初始化流量数组
    flows = [0.0] * pump_count
    
    # 计算总的有效频率
    total_frequency = sum(freq for _, freq in pump_info)
    
    if total_frequency > 0:
        # 按频率比例分配流量
        for pump_idx, frequency in pump_info:
            flow_ratio = frequency / total_frequency
            flows[pump_idx] = total_flow * flow_ratio
    
    return flows


def allocate_power_to_pumps_universal(row, power_config, pump_count=4):
    """
    通用功率分配算法：将电表功率分配到各个水泵
    
    该函数根据配置将电表功率分配给对应的水泵。
    分配原则：
    1. 只有运行状态>0且频率>0的水泵才参与功率分配
    2. 功率分配比例 = 该泵频率^2 / 同组运行泵频率^2之和（功率与频率平方成正比）
    3. 如果同组泵都不运行，则功率为0
    
    Args:
        row (pd.Series): 包含各泵频率、运行状态和电表功率的数据行
        power_config (dict): 功率配置，格式如：
            {
                'power_pump12': [1, 2],  # 电表power_pump12对应1、2号泵
                'power_pump34': [3, 4],  # 电表power_pump34对应3、4号泵
            }
            或者：
            {
                'power_pump3': [3],      # 电表power_pump3对应3号泵
                'power_pump4': [4],      # 电表power_pump4对应4号泵
            }
        pump_count (int): 水泵数量，默认4
    
    Returns:
        list: 各泵分配的功率列表
        
    Author: zq
    Date: 2025.01.08 17:35:00
    Version: 2.0
    """
    # 初始化功率数组
    powers = [0.0] * pump_count
    
    # 遍历每个电表配置
    for power_source, pump_list in power_config.items():
        total_power = row.get(power_source, 0)
        
        # 获取该组泵的运行信息
        group_pump_info = []
        for pump_id in pump_list:
            function = row.get(f'function_pump{pump_id}', 0)
            frequency = row.get(f'frequency_pump{pump_id}', 0)
            
            if function > 0 and frequency > 0:
                group_pump_info.append((pump_id - 1, frequency))  # 使用0-based索引
        
        # 计算该组泵的总频率平方
        total_freq_square = sum(freq**2 for _, freq in group_pump_info)
        
        if total_freq_square > 0:
            # 按频率平方比例分配功率
            for pump_idx, frequency in group_pump_info:
                power_ratio = (frequency**2) / total_freq_square
                powers[pump_idx] = total_power * power_ratio
        elif len(group_pump_info) > 0:
            # 频率为0但运行状态>0，平均分配
            power_per_pump = total_power / len(group_pump_info)
            for pump_idx, _ in group_pump_info:
                powers[pump_idx] = power_per_pump
    
    return powers


# 计算冷冻水泵的数据
def read_data_for_device_ChilledPump(start_time, end_time):
    '''
    多水泵数据处理函数
    
    该函数实现如下功能：
        1. 通过get_flow_report获取四个并联水泵的原始数据，字段重命名为标准列名
        2. 对各项传感器数据进行合理范围筛选，去除异常值
        3. 根据各泵运行状态和频率分配总流量到各个水泵
        4. 计算各泵的功率（1&2号泵共用一个电表，3&4号泵共用一个电表）
        5. 将数据分为两组：
           - 组1：各泵频率、流量、运行状态（用于流量模型训练）
           - 组2：各泵频率、功率、运行状态（用于功率模型训练）
        6. 保存原始数据和处理后的两组数据到csv文件
    
    Args:
        start_time (str): 数据起始时间，格式如 '2025-06-01 00:00:00'
        end_time (str): 数据结束时间，格式如 '2025-06-30 01:00:00'
    
    Returns:
        tuple: (data_flow_group, data_power_group) 两组处理后的数据
    '''
    id = 39

    # 使用模糊匹配模式，支持区分四个水泵的数据
    pattern_map = {
        r'冷冻泵1-运行反馈': 'function_pump1',
        r'冷冻泵2-运行反馈': 'function_pump2', 
        r'冷冻泵3-运行反馈': 'function_pump3',
        r'冷冻泵4-运行反馈': 'function_pump4',
        r'冷冻泵1-频率反馈': 'frequency_pump1',
        r'冷冻泵2-频率反馈': 'frequency_pump2',
        r'冷冻泵3-频率反馈': 'frequency_pump3', 
        r'冷冻泵4-频率反馈': 'frequency_pump4',
        r'冷冻泵电表1和2-功率.*': 'power_pump12',
        r'冷冻泵电表3和4-功率.*': 'power_pump34',
        r'冷冻总管热量表-累计流量': 'flow_total',
    }
    
    # 精确匹配的映射
    exact_rename_map = {
        "时间": "timestamp"
    }
    
    # 使用新的模糊搜索函数获取数据
    data_pump = get_flow_report_with_fuzzy_rename(
        id=id, 
        start_time=start_time, 
        end_time=end_time, 
        pattern_map=pattern_map,
        exact_rename_map=exact_rename_map
    )
    
    data_pump['flow_total'] = data_pump['flow_total'] * 6
    # 数据验证和异常处理
    logger.info(f"获取到的原始数据形状: {data_pump.shape}")
    logger.info(f"获取到的数据列: {data_pump.columns.tolist()}")
    
    # 检查必要字段是否存在
    required_fields = ['timestamp', 'flow_total']
    pump_fields = [f'function_pump{i}' for i in range(1, 5)] + [f'frequency_pump{i}' for i in range(1, 5)]
    power_fields = ['power_pump12', 'power_pump34']
    
    missing_fields = []
    for field in required_fields + pump_fields + power_fields:
        if field not in data_pump.columns:
            missing_fields.append(field)
    
    if missing_fields:
        logger.warning(f"缺失字段: {missing_fields}")
        # 为缺失的字段填充默认值
        for field in missing_fields:
            if 'function' in field:
                data_pump[field] = 0  # 运行状态默认为0
            elif 'frequency' in field:
                data_pump[field] = 0  # 频率默认为0
            elif 'power' in field:
                data_pump[field] = 0  # 功率默认为0
            elif field == 'flow_total':
                data_pump[field] = 0  # 总流量默认为0
    
    # 数据筛选 - 对各项传感器数据进行合理范围筛选
    # 计算时间差(秒)
    data_pump['time_diff'] = pd.to_datetime(data_pump['timestamp']).diff().dt.total_seconds()
    # 将累计流量差值除以时间差得到真实流量
    data_pump['flow_total'] = data_pump['flow_total'].diff() / data_pump['time_diff']
    data_pump = data_pump[
        (data_pump['flow_total'] >= 0) & (data_pump['flow_total'] <= 1000) &  # 总流量范围筛选
        (data_pump['power_pump12'] >= 0) & (data_pump['power_pump12'] <= 100) &  # 1&2号泵功率范围
        (data_pump['power_pump34'] >= 0) & (data_pump['power_pump34'] <= 100) &  # 3&4号泵功率范围
        (data_pump['frequency_pump1'] >= 0) & (data_pump['frequency_pump1'] <= 50) &  # 各泵频率范围
        (data_pump['frequency_pump2'] >= 0) & (data_pump['frequency_pump2'] <= 50) &
        (data_pump['frequency_pump3'] >= 0) & (data_pump['frequency_pump3'] <= 50) &
        (data_pump['frequency_pump4'] >= 0) & (data_pump['frequency_pump4'] <= 50)
    ]
    
    # 时间戳处理
    if isinstance(data_pump['timestamp'].iloc[0], str):
        data_pump['timestamp'] = pd.to_datetime(data_pump['timestamp'])
    

    # 保存原始数据
    data_pump.to_csv(os.path.join(OUTPUT_DIR, "pump_data_raw_multi.csv"), index=False)
    
    # 去掉缺失值和异常值inf
    data_pump = data_pump.dropna()
    numeric_cols = data_pump.select_dtypes(include=[np.number]).columns
    if len(numeric_cols) > 0:
        data_pump = data_pump[~np.isinf(data_pump[numeric_cols]).any(axis=1)]

    # 去除重复行
    logger.info("开始对水泵数据进行去重处理...")
    data_pump = remove_duplicate_rows(data_pump, window_size=5)
    
    # 流量分配算法：根据各泵运行状态和频率分配总流量
    logger.info("开始进行流量分配算法...")
    flow_allocations = data_pump.apply(
        lambda row: allocate_flow_to_pumps_universal(row, pump_count=4, min_frequency=10), 
        axis=1, result_type='expand'
    )
    flow_allocations.columns = ['flow_pump1', 'flow_pump2', 'flow_pump3', 'flow_pump4']
    data_pump = pd.concat([data_pump, flow_allocations], axis=1)
    logger.info("流量分配算法完成")
    
    # 功率分配算法：将电表功率分配到各个水泵
    logger.info("开始进行功率分配算法...")
    # 冷冻水泵功率配置：1&2号泵共用电表，3&4号泵共用电表
    chilled_power_config = {
        'power_pump12': [1, 2],
        'power_pump34': [3, 4]
    }
    power_allocations = data_pump.apply(
        lambda row: allocate_power_to_pumps_universal(row, chilled_power_config, pump_count=4), 
        axis=1, result_type='expand'
    )
    power_allocations.columns = ['power_pump1', 'power_pump2', 'power_pump3', 'power_pump4']
    data_pump = pd.concat([data_pump, power_allocations], axis=1)
    logger.info("功率分配算法完成")
    
    # 创建各个水泵的独立数据集
    pump_data_list = []
    
    for pump_id in range(1, 5):
        pump_data = data_pump[[
            'timestamp', 
            f'frequency_pump{pump_id}', 
            f'flow_pump{pump_id}', 
            f'power_pump{pump_id}',
            f'function_pump{pump_id}'
        ]].copy()
        
        # 重置索引以避免合并时的索引冲突
        pump_data = pump_data.reset_index(drop=True)
        
        # 重命名列以便统一处理
        pump_data = pump_data.rename(columns={
            f'frequency_pump{pump_id}': 'frequency',
            f'flow_pump{pump_id}': 'flow',
            f'power_pump{pump_id}': 'power',
            f'function_pump{pump_id}': 'function'
        })
        
        # 添加泵编号标识
        pump_data['pump_id'] = pump_id
        pump_data_list.append(pump_data)
    
    # 合并所有泵的数据
    if pump_data_list:
        combined_pump_data = pd.concat(pump_data_list, ignore_index=True)
    else:
        logger.error("没有有效的水泵数据可以合并")
        return pd.DataFrame(), pd.DataFrame()
    
    # 只保留运行状态为1的数据（可选，根据需要启用）
    # combined_pump_data = combined_pump_data[combined_pump_data['function'] == 1]
    
    # 分组1：频率、流量、运行状态（用于流量模型训练）
    data_flow_group = combined_pump_data[['timestamp', 'frequency', 'flow', 'function', 'pump_id']].copy()
    data_flow_group.to_csv(os.path.join(OUTPUT_DIR, "pump_flow_data_multi.csv"), index=False)
    
    # 分组2：频率、功率、运行状态（用于功率模型训练）
    data_power_group = combined_pump_data[['timestamp', 'frequency', 'power', 'function', 'pump_id']].copy()
    data_power_group.to_csv(os.path.join(OUTPUT_DIR, "pump_power_data_multi.csv"), index=False)
    
    # 保存各个水泵的详细数据
    data_pump.to_csv(os.path.join(OUTPUT_DIR, "pump_data_detailed_multi.csv"), index=False)
    
    logger.debug(f"流量模型数据形状: {data_flow_group.shape}")
    logger.debug(f"功率模型数据形状: {data_power_group.shape}")
    logger.debug(f"流量模型数据列: {data_flow_group.columns.tolist()}")
    logger.debug(f"功率模型数据列: {data_power_group.columns.tolist()}")
    
    return data_flow_group, data_power_group


# 计算冷却水泵的数据
def read_data_for_device_CoolingPump(start_time, end_time):
    '''
    冷却水泵数据处理函数
    
    该函数实现如下功能：
        1. 通过get_flow_report获取四个并联冷却水泵的原始数据，字段重命名为标准列名
        2. 对各项传感器数据进行合理范围筛选，去除异常值
        3. 根据各泵运行状态和频率分配总流量到各个水泵
        4. 计算各泵的功率（1&2号泵共用一个电表，3&4号泵共用一个电表）
        5. 将数据分为两组：
           - 组1：各泵频率、流量、运行状态（用于流量模型训练）
           - 组2：各泵频率、功率、运行状态（用于功率模型训练）
        6. 保存原始数据和处理后的两组数据到csv文件
    
    Args:
        start_time (str): 数据起始时间，格式如 '2025-06-01 00:00:00'
        end_time (str): 数据结束时间，格式如 '2025-06-30 01:00:00'
    
    Returns:
        tuple: (data_flow_group, data_power_group) 两组处理后的数据
    '''
    id = 40

    # 使用模糊匹配模式，支持区分四个冷却水泵的数据
    pattern_map = {
        r'冷却泵1-运行反馈': 'function_pump1',
        r'冷却泵2-运行反馈': 'function_pump2', 
        r'冷却泵3-运行反馈': 'function_pump3',
        r'冷却泵4-运行反馈': 'function_pump4',
        r'冷却泵1-频率反馈': 'frequency_pump1',
        r'冷却泵2-频率反馈': 'frequency_pump2',
        r'冷却泵3-频率反馈': 'frequency_pump3', 
        r'冷却泵4-频率反馈': 'frequency_pump4',
        r'冷却泵电表1和2-功率.*': 'power_pump12',
        r'冷却泵电表3-功率.*': 'power_pump3',
        r'冷却泵电表4-功率.*': 'power_pump4',
        r'冷却总管热量表-累计流量': 'flow_total',
    }
    
    # 精确匹配的映射
    exact_rename_map = {
        "时间": "timestamp"
    }
    
    # 使用新的模糊搜索函数获取数据
    data_pump = get_flow_report_with_fuzzy_rename(
        id=id, 
        start_time=start_time, 
        end_time=end_time, 
        pattern_map=pattern_map,
        exact_rename_map=exact_rename_map
    )
    
    data_pump['flow_total'] = data_pump['flow_total'] * 6
    # 数据验证和异常处理
    logger.info(f"获取到的原始数据形状: {data_pump.shape}")
    logger.info(f"获取到的数据列: {data_pump.columns.tolist()}")
    
    # 检查必要字段是否存在
    required_fields = ['timestamp', 'flow_total']
    pump_fields = [f'function_pump{i}' for i in range(1, 5)] + [f'frequency_pump{i}' for i in range(1, 5)]
    power_fields = ['power_pump12', 'power_pump3', 'power_pump4']
    
    missing_fields = []
    for field in required_fields + pump_fields + power_fields:
        if field not in data_pump.columns:
            missing_fields.append(field)
    
    if missing_fields:
        logger.warning(f"缺失字段: {missing_fields}")
        # 为缺失的字段填充默认值
        for field in missing_fields:
            if 'function' in field:
                data_pump[field] = 0  # 运行状态默认为0（停止）
            elif 'frequency' in field:
                data_pump[field] = 0  # 频率默认为0
            elif 'power' in field:
                data_pump[field] = 0  # 功率默认为0
            elif field == 'flow_total':
                data_pump[field] = 0  # 流量默认为0
    
    # 数据类型转换和清理
    data_pump['timestamp'] = pd.to_datetime(data_pump['timestamp'])
    
    # 数值列转换为float类型
    numeric_columns = ['flow_total'] + pump_fields + power_fields
    for col in numeric_columns:
        if col in data_pump.columns:
            data_pump[col] = pd.to_numeric(data_pump[col], errors='coerce')
    
    # 数据筛选：去除异常值
    logger.info("开始数据筛选...")
    original_count = len(data_pump)
    
    # 筛选条件
    filter_conditions = (
        (data_pump['flow_total'] >= 0) & (data_pump['flow_total'] <= 2000) &  # 流量范围
        (data_pump['frequency_pump1'] >= 0) & (data_pump['frequency_pump1'] <= 60) &  # 频率范围
        (data_pump['frequency_pump2'] >= 0) & (data_pump['frequency_pump2'] <= 60) &
        (data_pump['frequency_pump3'] >= 0) & (data_pump['frequency_pump3'] <= 60) &
        (data_pump['frequency_pump4'] >= 0) & (data_pump['frequency_pump4'] <= 60) &
        (data_pump['power_pump12'] >= 0) & (data_pump['power_pump12'] <= 100) &  # 功率范围
        (data_pump['power_pump3'] >= 0) & (data_pump['power_pump3'] <= 50) &
        (data_pump['power_pump4'] >= 0) & (data_pump['power_pump4'] <= 50)
    )
    
    data_pump = data_pump[filter_conditions]
    filtered_count = len(data_pump)
    logger.info(f"数据筛选完成，保留 {filtered_count}/{original_count} 条记录")
    
    # 去除重复数据
    data_pump = remove_duplicate_rows(data_pump, window_size=5)
    deduplicated_count = len(data_pump)
    logger.info(f"去重完成，保留 {deduplicated_count} 条记录")
    
    # 保存原始处理后的数据
    raw_output_path = os.path.join(OUTPUT_DIR, 'load_data_CoolingPump_raw.csv')
    data_pump.to_csv(raw_output_path, index=False, encoding='utf-8-sig')
    logger.info(f"原始数据已保存到: {raw_output_path}")
    
    # 应用流量分配算法
    logger.info("开始流量分配计算...")
    flow_allocations = data_pump.apply(
        lambda row: allocate_flow_to_pumps_universal(row, pump_count=4, min_frequency=0), 
        axis=1, result_type='expand'
    )
    flow_allocations.columns = ['flow_pump1', 'flow_pump2', 'flow_pump3', 'flow_pump4']
    data_pump = pd.concat([data_pump, flow_allocations], axis=1)
    logger.info("流量分配算法完成")
    
    # 应用功率分配算法
    logger.info("开始功率分配计算...")
    # 冷却水泵功率配置：1&2号泵共用电表，3&4号泵各自独立
    cooling_power_config = {
        'power_pump12': [1, 2],  # 1&2号泵共用电表
        'power_pump3': [3],      # 3号泵独立电表
        'power_pump4': [4]       # 4号泵独立电表
    }
    power_allocations = data_pump.apply(
        lambda row: allocate_power_to_pumps_universal(row, cooling_power_config, pump_count=4), 
        axis=1, result_type='expand'
    )
    power_allocations.columns = ['power_pump1', 'power_pump2', 'power_pump3', 'power_pump4']
    data_pump = pd.concat([data_pump, power_allocations], axis=1)
    logger.info("功率分配算法完成")
    
    # 创建各个水泵的独立数据集（与冷冻水泵保持一致的长格式结构）
    logger.info("创建各个水泵的独立数据集...")
    
    # 创建空的合并数据框
    combined_data_list = []
    
    for pump_id in range(1, 5):
        # 为当前泵创建数据记录，直接遍历DataFrame行
        for idx, row in data_pump.iterrows():
            # 确保提取的值是标量而不是Series对象
            power_value = row[f'power_pump{pump_id}']
            if isinstance(power_value, (pd.Series, np.ndarray)):
                # 如果是Series或数组，取第一个值
                power_value = float(power_value.iloc[0] if hasattr(power_value, 'iloc') else power_value[0])
            else:
                power_value = float(power_value)
            
            combined_data_list.append({
                'timestamp': row['timestamp'],
                'frequency': float(row[f'frequency_pump{pump_id}']),
                'flow': float(row[f'flow_pump{pump_id}']),
                'power': power_value,
                'function': float(row[f'function_pump{pump_id}']),
                'pump_id': pump_id
            })
    
    # 创建合并后的DataFrame
    combined_pump_data = pd.DataFrame(combined_data_list)
    
    # 只保留运行状态为1的数据（可选，根据需要启用）
    # combined_pump_data = combined_pump_data[combined_pump_data['function'] == 1]
    
    # 分组1：频率、流量、运行状态（用于流量模型训练）
    data_flow_group = combined_pump_data[['timestamp', 'frequency', 'flow', 'function', 'pump_id']].copy()
    
    # 分组2：频率、功率、运行状态（用于功率模型训练）
    data_power_group = combined_pump_data[['timestamp', 'frequency', 'power', 'function', 'pump_id']].copy()
    
    # 数据清理：去除缺失值和无穷值
    logger.info("清理数据中的缺失值和异常值...")
    
    # 流量组清理
    flow_before = len(data_flow_group)
    data_flow_group = data_flow_group.dropna()
    # 使用更安全的方法处理无穷值
    data_flow_group = data_flow_group[~data_flow_group.isin([np.inf, -np.inf]).any(axis=1)]
    flow_after = len(data_flow_group)
    logger.info(f"流量组数据清理：{flow_before} -> {flow_after} 条记录")
    
    # 功率组清理
    power_before = len(data_power_group)
    data_power_group = data_power_group.dropna()
    # 使用更安全的方法处理无穷值
    data_power_group = data_power_group[~data_power_group.isin([np.inf, -np.inf]).any(axis=1)]
    power_after = len(data_power_group)
    logger.info(f"功率组数据清理：{power_before} -> {power_after} 条记录")
    
    # 保存处理后的数据（与冷冻水泵保持一致的文件命名格式）
    data_flow_group.to_csv(os.path.join(OUTPUT_DIR, "cooling_pump_flow_data_multi.csv"), index=False)
    data_power_group.to_csv(os.path.join(OUTPUT_DIR, "cooling_pump_power_data_multi.csv"), index=False)
    
    # 保存各个水泵的详细数据
    data_pump.to_csv(os.path.join(OUTPUT_DIR, "cooling_pump_data_detailed_multi.csv"), index=False)
    
    logger.info(f"流量训练数据已保存到: {os.path.join(OUTPUT_DIR, 'cooling_pump_flow_data_multi.csv')}")
    logger.info(f"功率训练数据已保存到: {os.path.join(OUTPUT_DIR, 'cooling_pump_power_data_multi.csv')}")
    
    # 数据统计信息
    logger.info("\n=== 冷却水泵数据处理完成 ===")
    logger.info(f"流量组数据形状: {data_flow_group.shape}")
    logger.info(f"功率组数据形状: {data_power_group.shape}")
    
    # 统计各泵运行情况
    for i in range(1, 5):
        running_count = (data_pump[f'function_pump{i}'] > 0).sum()
        total_count = len(data_pump)
        logger.info(f"冷却泵{i}运行时间占比: {running_count}/{total_count} ({running_count/total_count*100:.1f}%)")
    
    return data_flow_group, data_power_group


# 计算冷却水泵的数据
def read_data_for_device_CoolingPump_new(start_time, end_time):
    '''
    冷却水泵数据处理函数
    
    该函数实现如下功能：
        1. 通过get_flow_report获取四个并联冷却水泵的原始数据，字段重命名为标准列名
        2. 对各项传感器数据进行合理范围筛选，去除异常值
        3. 根据各泵运行状态和频率分配总流量到各个水泵
        4. 计算各泵的功率（1&2号泵共用一个电表，3&4号泵共用一个电表）
        5. 将数据分为两组：
           - 组1：各泵频率、流量、运行状态（用于流量模型训练）
           - 组2：各泵频率、功率、运行状态（用于功率模型训练）
        6. 保存原始数据和处理后的两组数据到csv文件
    
    Args:
        start_time (str): 数据起始时间，格式如 '2025-06-01 00:00:00'
        end_time (str): 数据结束时间，格式如 '2025-06-30 01:00:00'
    
    Returns:
        tuple: (data_flow_group, data_power_group) 两组处理后的数据
    '''
    id = 4

    # 使用模糊匹配模式，支持区分四个冷却水泵的数据
    pattern_map = {
        r'1#冷却泵-频率反馈.*': 'frequency_pump1',
        r'2#冷却泵-频率反馈.*': 'frequency_pump2',
        r'3#冷却泵-频率反馈.*': 'frequency_pump3', 
        r'4#冷却泵-频率反馈.*': 'frequency_pump4',
        r'1#冷却泵.*-功率.*': 'power_pump1',
        r'2#冷却泵.*-功率.*': 'power_pump2',
        r'3#冷却泵.*-功率.*': 'power_pump3',
        r'4#冷却泵.*-功率.*': 'power_pump4',
        r'冷却总管热量表.*瞬时流量.*': 'flow_total',
    }
    
    # 精确匹配的映射
    exact_rename_map = {
        "时间": "timestamp"
    }
    
    # 使用新的模糊搜索函数获取数据
    data_pump = get_flow_report_with_fuzzy_rename(
        id=id, 
        start_time=start_time, 
        end_time=end_time, 
        pattern_map=pattern_map,
        exact_rename_map=exact_rename_map
    )
    
    # 数据验证和异常处理
    logger.info(f"获取到的原始数据形状: {data_pump.shape}")
    logger.info(f"获取到的数据列: {data_pump.columns.tolist()}")
    
    # 检查必要字段是否存在
    required_fields = ['timestamp', 'flow_total']
    pump_fields = [f'frequency_pump{i}' for i in range(1, 5)]
    power_fields = ['power_pump1', 'power_pump2', 'power_pump3', 'power_pump4']
    
    missing_fields = []
    for field in required_fields + pump_fields + power_fields:
        if field not in data_pump.columns:
            missing_fields.append(field)
    
    if missing_fields:
        logger.warning(f"缺失字段: {missing_fields}")
        # 为缺失的字段填充默认值
        for field in missing_fields:
            if 'frequency' in field:
                data_pump[field] = 0  # 频率默认为0
            elif 'power' in field:
                data_pump[field] = 0  # 功率默认为0
            elif field == 'flow_total':
                data_pump[field] = 0  # 流量默认为0
    
    # 数据类型转换和清理
    data_pump['timestamp'] = pd.to_datetime(data_pump['timestamp'])
    
    # 数值列转换为float类型
    numeric_columns = ['flow_total'] + pump_fields + power_fields
    for col in numeric_columns:
        if col in data_pump.columns:
            data_pump[col] = pd.to_numeric(data_pump[col], errors='coerce')
    
    # 数据筛选：去除异常值
    logger.info("开始数据筛选...")
    original_count = len(data_pump)
    
    # 筛选条件
    filter_conditions = (
        (data_pump['flow_total'] >= 0) & (data_pump['flow_total'] <= 2000) &  # 流量范围
        (data_pump['frequency_pump1'] >= 0) & (data_pump['frequency_pump1'] <= 50) &  # 频率范围
        (data_pump['frequency_pump2'] >= 0) & (data_pump['frequency_pump2'] <= 50) &
        (data_pump['frequency_pump3'] >= 0) & (data_pump['frequency_pump3'] <= 50) &
        (data_pump['frequency_pump4'] >= 0) & (data_pump['frequency_pump4'] <= 50) &
        (data_pump['power_pump1'] >= 0) & (data_pump['power_pump1'] <= 50) &  # 功率范围
        (data_pump['power_pump2'] >= 0) & (data_pump['power_pump2'] <= 50) &
        (data_pump['power_pump3'] >= 0) & (data_pump['power_pump3'] <= 50) &
        (data_pump['power_pump4'] >= 0) & (data_pump['power_pump4'] <= 50)
    )
    
    data_pump = data_pump[filter_conditions]
    filtered_count = len(data_pump)
    logger.info(f"数据筛选完成，保留 {filtered_count}/{original_count} 条记录")
    
    # 去除重复数据
    data_pump = remove_duplicate_rows(data_pump, window_size=5)
    deduplicated_count = len(data_pump)
    logger.info(f"去重完成，保留 {deduplicated_count} 条记录")
    
    # 保存原始处理后的数据
    raw_output_path = os.path.join(OUTPUT_DIR, 'load_data_CoolingPump_raw.csv')
    data_pump.to_csv(raw_output_path, index=False, encoding='utf-8-sig')
    logger.info(f"原始数据已保存到: {raw_output_path}")
    
    # 应用流量分配算法
    logger.info("开始流量分配计算...")
    flow_allocations = data_pump.apply(
        lambda row: allocate_flow_to_pumps_universal(row, pump_count=4, min_frequency=0), 
        axis=1, result_type='expand'
    )
    flow_allocations.columns = ['flow_pump1', 'flow_pump2', 'flow_pump3', 'flow_pump4']
    data_pump = pd.concat([data_pump, flow_allocations], axis=1)
    logger.info("流量分配算法完成")
    
    # 应用功率分配算法
    logger.info("开始功率分配计算...")
    # 冷却水泵功率配置
    cooling_power_config = {
        'power_pump1': [1],  
        'power_pump2': [2],      
        'power_pump3': [3],       
        'power_pump4': [4]       
    }
    power_allocations = data_pump.apply(
        lambda row: allocate_power_to_pumps_universal(row, cooling_power_config, pump_count=4), 
        axis=1, result_type='expand'
    )
    power_allocations.columns = ['power_pump1', 'power_pump2', 'power_pump3', 'power_pump4']
    data_pump = pd.concat([data_pump, power_allocations], axis=1)
    logger.info("功率分配算法完成")
    
    # 创建各个水泵的独立数据集（与冷冻水泵保持一致的长格式结构）
    logger.info("创建各个水泵的独立数据集...")
    
    # 创建空的合并数据框
    combined_data_list = []
    
    for pump_id in range(1, 5):
        # 为当前泵创建数据记录，直接遍历DataFrame行
        for idx, row in data_pump.iterrows():
            # 确保提取的值是标量而不是Series对象
            power_value = row[f'power_pump{pump_id}']
            if isinstance(power_value, (pd.Series, np.ndarray)):
                # 如果是Series或数组，取第一个值
                power_value = float(power_value.iloc[0] if hasattr(power_value, 'iloc') else power_value[0])
            else:
                power_value = float(power_value)
            
            combined_data_list.append({
                'timestamp': row['timestamp'],
                'frequency': float(row[f'frequency_pump{pump_id}']),
                'flow': float(row[f'flow_pump{pump_id}']),
                'power': power_value,
                'function': float(row[f'function_pump{pump_id}']),
                'pump_id': pump_id
            })
    
    # 创建合并后的DataFrame
    combined_pump_data = pd.DataFrame(combined_data_list)
    
    # 只保留运行状态为1的数据（可选，根据需要启用）
    # combined_pump_data = combined_pump_data[combined_pump_data['function'] == 1]
    
    # 分组1：频率、流量、运行状态（用于流量模型训练）
    data_flow_group = combined_pump_data[['timestamp', 'frequency', 'flow', 'function', 'pump_id']].copy()
    
    # 分组2：频率、功率、运行状态（用于功率模型训练）
    data_power_group = combined_pump_data[['timestamp', 'frequency', 'power', 'function', 'pump_id']].copy()
    
    # 数据清理：去除缺失值和无穷值
    logger.info("清理数据中的缺失值和异常值...")
    
    # 流量组清理
    flow_before = len(data_flow_group)
    data_flow_group = data_flow_group.dropna()
    # 使用更安全的方法处理无穷值
    data_flow_group = data_flow_group[~data_flow_group.isin([np.inf, -np.inf]).any(axis=1)]
    flow_after = len(data_flow_group)
    logger.info(f"流量组数据清理：{flow_before} -> {flow_after} 条记录")
    
    # 功率组清理
    power_before = len(data_power_group)
    data_power_group = data_power_group.dropna()
    # 使用更安全的方法处理无穷值
    data_power_group = data_power_group[~data_power_group.isin([np.inf, -np.inf]).any(axis=1)]
    power_after = len(data_power_group)
    logger.info(f"功率组数据清理：{power_before} -> {power_after} 条记录")
    
    # 保存处理后的数据（与冷冻水泵保持一致的文件命名格式）
    data_flow_group.to_csv(os.path.join(OUTPUT_DIR, "cooling_pump_flow_data_multi.csv"), index=False)
    data_power_group.to_csv(os.path.join(OUTPUT_DIR, "cooling_pump_power_data_multi.csv"), index=False)
    
    # 保存各个水泵的详细数据
    data_pump.to_csv(os.path.join(OUTPUT_DIR, "cooling_pump_data_detailed_multi.csv"), index=False)
    
    logger.info(f"流量训练数据已保存到: {os.path.join(OUTPUT_DIR, 'cooling_pump_flow_data_multi.csv')}")
    logger.info(f"功率训练数据已保存到: {os.path.join(OUTPUT_DIR, 'cooling_pump_power_data_multi.csv')}")
    
    # 数据统计信息
    logger.info("\n=== 冷却水泵数据处理完成 ===")
    logger.info(f"流量组数据形状: {data_flow_group.shape}")
    logger.info(f"功率组数据形状: {data_power_group.shape}")
    
    # 统计各泵运行情况
    for i in range(1, 5):
        running_count = (data_pump[f'function_pump{i}'] > 0).sum()
        total_count = len(data_pump)
        logger.info(f"冷却泵{i}运行时间占比: {running_count}/{total_count} ({running_count/total_count*100:.1f}%)")
    
    return data_flow_group, data_power_group
    
'''
def read_data_for_device_CoolingTower(start_time, end_time):
    """
    冷却塔数据处理函数
    
    该函数实现如下功能：
        1. 通过get_flow_report获取冷却塔系统的原始数据，字段重命名为标准列名
        2. 将原始数据按冷却塔编号拆分为独立的冷却塔数据
        3. 为每个冷却塔分配对应的水流量（基于频率比例分配总流量）
        4. 计算每个冷却塔的功耗（基于频率比例分配总功耗）
        5. 对各项传感器数据进行合理范围筛选，去除异常值
        6. 生成两种专用训练数据集：换热性能模型和风机能耗模型
        7. 保存原始数据和处理后的各冷却塔数据到csv文件
    
    Args:
        start_time (str): 数据起始时间，格式如 '2025-06-01 00:00:00'
        end_time (str): 数据结束时间，格式如 '2025-06-30 01:00:00'
    
    Returns:
        dict: 包含三种数据集的字典：
            - 'original_data': 原始处理后的冷却塔数据，键为冷却塔编号
            - 'heat_transfer_data': 换热性能模型训练数据，包含换热量、效率、冷却范围等
            - 'fan_energy_data': 风机能耗模型训练数据，包含比功耗、功率系数、频率系数等
    
    数据集说明：
        换热性能模型数据集字段：
            - timestamp: 时间戳
            - flow: 流量 (m³/h)
            - temp_diff: 温差 (供水温度-湿球温度) (℃)
            - enthalpy_diff: 焓差 (使用供水温度和100%相对湿度计算的焓值-原焓值) (kJ/kg)
            - frequency: 风机频率 (Hz)
            - heat_transfer_rate: 换热量 (kW)
        
        风机能耗模型数据集字段：
            - timestamp: 时间戳
            - frequency: 频率 (Hz)
            - power: 功率 (kW)
    
    Raises:
        ValueError: 当数据获取或处理过程中出现问题时
    
    作者: zq
    日期: 
    版本: 2.0
    """
    
    # 设置流报表ID（需要根据实际情况调整）
    id = 41  # 冷却塔数据的流报表ID
    
    # 使用模糊匹配模式，匹配冷却塔相关字段
    pattern_map = {
        r'冷却塔1.*频率.*': 'frequency_tower1',
        r'冷却塔2.*频率.*': 'frequency_tower2', 
        r'冷却塔3.*频率.*': 'frequency_tower3',
        r'冷却塔4.*频率.*': 'frequency_tower4',
        r'冷却.*热量表.*流量': 'flow_total',
        r'冷却.*热量表.*回水温度': 'temp_return',
        r'冷却.*热量表.*供水温度': 'temp_supply',
        r'冷却.*热量表.*总.*热量': 'heat_total',
        r'冷却塔.*功率.*': 'power_total',
        #r'冷源-湿球温度': 'wet_bulb_temp',
        #r'冷源-焓值': 'enthalpy'
    }
    
    # 精确匹配的映射
    exact_rename_map = {
        '冷源-湿球温度': 'wet_bulb_temp',
        '冷源-焓值': 'enthalpy',
        "时间": "timestamp"
    }
    
    # 使用模糊搜索函数获取数据
    data_cooling_tower = get_flow_report_with_fuzzy_rename(
        id=id, 
        start_time=start_time, 
        end_time=end_time, 
        pattern_map=pattern_map,
        exact_rename_map=exact_rename_map
    )
    data_cooling_tower['heat_total'] = data_cooling_tower['heat_total']*6
    # 数据验证和异常处理
    logger.info(f"获取到的冷却塔原始数据形状: {data_cooling_tower.shape}")
    logger.info(f"获取到的数据列: {data_cooling_tower.columns.tolist()}")
    
    # 检查必要字段是否存在
    required_fields = ['timestamp', 'flow_total', 'temp_return', 'temp_supply', 
                      'heat_total', 'power_total', 'wet_bulb_temp', 'enthalpy']
    tower_fields = [f'frequency_tower{i}' for i in range(1, 5)]
    
    missing_fields = []
    for field in required_fields + tower_fields:
        if field not in data_cooling_tower.columns:
            missing_fields.append(field)
    
    if missing_fields:
        logger.warning(f"缺失字段: {missing_fields}")
        # 为缺失的字段填充默认值
        for field in missing_fields:
            if 'frequency' in field:
                data_cooling_tower[field] = 0
            else:
                data_cooling_tower[field] = np.nan
    
    # 确保timestamp列为datetime类型
    if isinstance(data_cooling_tower['timestamp'].iloc[0], str):
        data_cooling_tower['timestamp'] = pd.to_datetime(data_cooling_tower['timestamp'])
    
    # 数据预处理：处理异常值和缺失值
    original_count = len(data_cooling_tower)
    logger.info(f"原始数据记录数: {original_count}")
    
    # 数据筛选条件
    filter_conditions = (
        (data_cooling_tower['temp_return'] >= 0) & (data_cooling_tower['temp_return'] <= 50) &
        (data_cooling_tower['temp_supply'] >= 0) & (data_cooling_tower['temp_supply'] <= 50) &
        (data_cooling_tower['flow_total'] >= 10) & (data_cooling_tower['flow_total'] <= 1000) &
        (data_cooling_tower['power_total'] >= 0) & (data_cooling_tower['power_total'] <= 200) &
        (data_cooling_tower['wet_bulb_temp'] >= -10) & (data_cooling_tower['wet_bulb_temp'] <= 50) &
        (data_cooling_tower['frequency_tower1'] >= 0) & (data_cooling_tower['frequency_tower1'] <= 60) &
        (data_cooling_tower['frequency_tower2'] >= 0) & (data_cooling_tower['frequency_tower2'] <= 60) &
        (data_cooling_tower['frequency_tower3'] >= 0) & (data_cooling_tower['frequency_tower3'] <= 60) &
        (data_cooling_tower['frequency_tower4'] >= 0) & (data_cooling_tower['frequency_tower4'] <= 60)
    )
    
    data_cooling_tower = data_cooling_tower[filter_conditions]
    filtered_count = len(data_cooling_tower)
    logger.info(f"数据筛选完成，保留 {filtered_count}/{original_count} 条记录")
    
    # 去除重复数据
    data_cooling_tower = remove_duplicate_rows(data_cooling_tower, window_size=5)
    deduplicated_count = len(data_cooling_tower)
    logger.info(f"去重完成，保留 {deduplicated_count} 条记录")
    
    # 保存原始处理后的数据
    raw_output_path = os.path.join(OUTPUT_DIR, 'load_data_CoolingTower_raw.csv')
    data_cooling_tower.to_csv(raw_output_path, index=False, encoding='utf-8-sig')
    logger.info(f"原始数据已保存到: {raw_output_path}")
    
    # 计算各冷却塔的流量和功耗分配
    logger.info("开始计算各冷却塔的流量和功耗分配...")
    
    # 计算总频率（用于流量比例分配）
    data_cooling_tower['total_frequency'] = (
        data_cooling_tower['frequency_tower1'] + 
        data_cooling_tower['frequency_tower2'] + 
        data_cooling_tower['frequency_tower3'] + 
        data_cooling_tower['frequency_tower4']
    )
    
    # 计算总频率的2次方（用于功耗比例分配）
    data_cooling_tower['total_frequency_squared'] = (
        data_cooling_tower['frequency_tower1']**2 + 
        data_cooling_tower['frequency_tower2']**2 + 
        data_cooling_tower['frequency_tower3']**2+ 
        data_cooling_tower['frequency_tower4']**2
    )
    
    # 避免除零错误
    data_cooling_tower['total_frequency'] = data_cooling_tower['total_frequency'].replace(0, np.nan)
    data_cooling_tower['total_frequency_squared'] = data_cooling_tower['total_frequency_squared'].replace(0, np.nan)
    
    # 添加换热量分配逻辑（在数据拆分之前进行）
    logger.info("开始进行换热量分配计算...")
    
    # 为每个冷却塔初始化分配的换热量列
    for tower_id in range(1, 5):
        data_cooling_tower[f'allocated_heat_tower{tower_id}'] = 0.0
    
    # 遍历每一行数据，判断是否为有效数据并分配换热量
    for idx in data_cooling_tower.index:
        # 获取当前时刻所有冷却塔的频率
        freq_values = [
            data_cooling_tower.loc[idx, 'frequency_tower1'],
            data_cooling_tower.loc[idx, 'frequency_tower2'],
            data_cooling_tower.loc[idx, 'frequency_tower3'],
            data_cooling_tower.loc[idx, 'frequency_tower4']
        ]
        
        # 筛选出开启的冷却塔（频率大于25Hz）
        running_freqs = [f for f in freq_values if f > 25.0]
        running_tower_ids = [i+1 for i, f in enumerate(freq_values) if f > 25.0]
        
        # 判断是否为有效数据：开启冷却塔数量大于1且频率差值小于2Hz
        if len(running_freqs) >= 1:
            max_freq = max(running_freqs)
            min_freq = min(running_freqs)
            freq_diff = max_freq - min_freq
            
            # 有效数据：频率差值小于2Hz
            if freq_diff <= 5.0:
                # 获取总换热量
                total_heat = data_cooling_tower.loc[idx, 'heat_total']
                
                # 为运行中的冷却塔平分总换热量
                if total_heat > 0:
                    allocated_heat_per_tower = total_heat / len(running_freqs)
                    for tower_id in running_tower_ids:
                        data_cooling_tower.loc[idx, f'allocated_heat_tower{tower_id}'] = allocated_heat_per_tower
    
    logger.info("换热量分配计算完成")
    
    # 为每个冷却塔分配流量和功耗
    cooling_tower_data = {}
    
    for tower_id in range(1, 5):
        logger.info(f"处理冷却塔{tower_id}数据...")
        
        # 创建单个冷却塔的数据框
        tower_data = data_cooling_tower[['timestamp', 'temp_return', 'temp_supply', 
                                       'flow_total', 'heat_total', 'power_total', 
                                       'wet_bulb_temp', 'enthalpy', 'total_frequency', 'total_frequency_squared',
                                       f'frequency_tower{tower_id}', f'allocated_heat_tower{tower_id}']].copy()
        
        # 重命名列
        tower_data = tower_data.rename(columns={
            f'frequency_tower{tower_id}': 'frequency',
            'temp_return': 'cooling_return_temp',
            'temp_supply': 'cooling_supply_temp',
            'flow_total': 'total_flow',
            'heat_total': 'total_heat',
            'power_total': 'total_power',
            f'allocated_heat_tower{tower_id}': 'allocated_heat'
        })
        
        # 计算该冷却塔的流量分配（频率大于25Hz的冷却塔平分流量）
        # 首先计算所有冷却塔中频率大于25Hz的数量
        running_towers_count = np.zeros(len(tower_data))
        for tid in range(1, 5):
            if tid == tower_id:
                freq_values = tower_data['frequency']
            else:
                freq_values = data_cooling_tower[f'frequency_tower{tid}'].loc[tower_data.index]
            
            running_mask = freq_values > 25.0
            running_towers_count += running_mask.astype(int)
        
        # 流量分配：频率大于25Hz的冷却塔平分总流量
        tower_data['flow'] = np.where(
            (tower_data['frequency'] >= 25.0) & (running_towers_count > 0),
            tower_data['total_flow'] / running_towers_count,
            0
        )
        
        # 计算该冷却塔的功耗分配（基于频率的2次方比例，但只对运行中的冷却塔分配）
        # 只有当该冷却塔频率大于5Hz时才认为在运行
        tower_running = tower_data['frequency'] > 5.0
        
        # 计算运行中冷却塔的频率2次方总和
        running_freq_squared_sum = np.zeros(len(tower_data))
        for tid in range(1, 5):
            freq_col = f'frequency_tower{tid}' if tid != tower_id else 'frequency'
            if tid == tower_id:
                freq_values = tower_data['frequency']
            else:
                freq_values = data_cooling_tower[f'frequency_tower{tid}'].loc[tower_data.index]
            
            running_mask = freq_values > 5.0
            running_freq_squared_sum += np.where(running_mask, freq_values**2, 0)
        
        # 功耗分配：只有运行中的冷却塔才分配功耗（基于频率2次方比例）
        tower_data['power'] = np.where(
            tower_running & (running_freq_squared_sum > 0),
            tower_data['total_power'] * (tower_data['frequency']**2) / running_freq_squared_sum,
            0
        )
        
        # 选择最终需要的字段
        final_columns = ['timestamp', 'flow', 'frequency', 'power', 
                        'cooling_supply_temp', 'cooling_return_temp', 
                        'total_flow', 'wet_bulb_temp', 'enthalpy', 'allocated_heat']
        
        tower_data_final = tower_data[final_columns].copy()
        
        # 去除缺失值
        tower_data_final = tower_data_final.dropna()
        
        # 筛选有效运行数据（频率大于0）
        tower_data_final = tower_data_final[tower_data_final['frequency'] >= 25]
        
        logger.info(f"冷却塔{tower_id}有效数据点数: {len(tower_data_final)}")
        
        # 保存单个冷却塔数据
        tower_output_path = os.path.join(OUTPUT_DIR, f'cooling_tower_{tower_id}_data.csv')
        tower_data_final.to_csv(tower_output_path, index=False, encoding='utf-8-sig')
        logger.info(f"冷却塔{tower_id}数据已保存到: {tower_output_path}")
        
        # 存储到结果字典
        cooling_tower_data[f'tower_{tower_id}'] = tower_data_final
    
    # 生成两种不同的训练数据集
    logger.info("\n=== 生成专用训练数据集 ===")
    
    # 1. 换热性能模型训练数据集
    heat_transfer_data = {}
    fan_energy_data = {}
    
    for tower_id in range(1, 5):
        tower_key = f'tower_{tower_id}'
        if tower_key in cooling_tower_data and len(cooling_tower_data[tower_key]) > 0:
            tower_data = cooling_tower_data[tower_key].copy()
            
            # 换热性能模型数据集 - 关注换热效果
            # 计算温差 (供水温度-湿球温度)
            tower_data['temp_diff'] = tower_data['cooling_supply_temp'] - tower_data['wet_bulb_temp']
            
            # 计算焓差 (使用供水温度和100%相对湿度计算的焓值 - 原焓值)
            tower_data['enthalpy_supply_100rh'] = calc_air_enthalpy_by_t_rh(
                tower_data['cooling_supply_temp'], 100.0
            )
            tower_data['enthalpy_diff'] = tower_data['enthalpy_supply_100rh'] - tower_data['enthalpy']
            
            # 换热量分配逻辑已在数据拆分前完成，这里直接使用预分配的换热量
            
            # 计算换热量 (kW) - 仅使用分配的换热量
            # 只有当allocated_heat存在且大于0时才保留数据，否则设为NaN
            tower_data['heat_transfer_rate'] = np.where(
                (tower_data['allocated_heat'].notna()) & (tower_data['allocated_heat'] > 0),
                tower_data['allocated_heat'],
                np.nan
            )
            
            # 记录换热量计算方式的统计信息
            valid_count = ((tower_data['allocated_heat'].notna()) & (tower_data['allocated_heat'] > 0)).sum()
            invalid_count = len(tower_data) - valid_count
            logger.info(f"冷却塔{tower_id}: 有效分配换热量 {valid_count} 行，无效数据 {invalid_count} 行")
            
            # 过滤掉无效数据（换热量为NaN的行）
            tower_data = tower_data.dropna(subset=['heat_transfer_rate'])
            logger.info(f"冷却塔{tower_id}: 过滤后剩余 {len(tower_data)} 行有效数据")
            
            # 换热性能模型所需字段
            heat_transfer_final_columns = [
                'timestamp', 'flow', 'temp_diff', 'enthalpy_diff', 
                'frequency', 'heat_transfer_rate'
            ]
            
            heat_transfer_tower_data = tower_data[heat_transfer_final_columns].copy()
            
            # 风机能耗模型数据集 - 关注能耗与运行参数关系
            # 风机能耗模型所需字段
            fan_energy_final_columns = [
                'timestamp', 'frequency', 'power'
            ]
            
            fan_energy_tower_data = tower_data[fan_energy_final_columns].copy()
            
            # 数据质量检查和清理
            # 换热性能数据清理
            heat_transfer_tower_data = heat_transfer_tower_data.dropna()
            heat_transfer_tower_data = heat_transfer_tower_data[
                (heat_transfer_tower_data['heat_transfer_rate'] >= 0) &
                (heat_transfer_tower_data['flow'] > 0) &
                (heat_transfer_tower_data['frequency'] > 0)
            ]
            
            # 风机能耗数据清理
            fan_energy_tower_data = fan_energy_tower_data.dropna()
            fan_energy_tower_data = fan_energy_tower_data[
                (fan_energy_tower_data['power'] >= 0) &
                (fan_energy_tower_data['frequency'] > 0)
            ]
            
            # 存储到结果字典
            heat_transfer_data[tower_key] = heat_transfer_tower_data
            fan_energy_data[tower_key] = fan_energy_tower_data
            
            logger.info(f"冷却塔{tower_id}换热性能数据点数: {len(heat_transfer_tower_data)}")
            logger.info(f"冷却塔{tower_id}风机能耗数据点数: {len(fan_energy_tower_data)}")
    
    # 保存换热性能模型训练数据
    logger.info("\n=== 保存换热性能模型训练数据 ===")
    for tower_id in range(1, 5):
        tower_key = f'tower_{tower_id}'
        if tower_key in heat_transfer_data and len(heat_transfer_data[tower_key]) > 0:
            heat_transfer_output_path = os.path.join(OUTPUT_DIR, f'cooling_tower_{tower_id}_heat_transfer_training.csv')
            heat_transfer_data[tower_key].to_csv(heat_transfer_output_path, index=False, encoding='utf-8-sig')
            logger.info(f"冷却塔{tower_id}换热性能训练数据已保存到: {heat_transfer_output_path}")
    
    # 保存风机能耗模型训练数据
    logger.info("\n=== 保存风机能耗模型训练数据 ===")
    for tower_id in range(1, 5):
        tower_key = f'tower_{tower_id}'
        if tower_key in fan_energy_data and len(fan_energy_data[tower_key]) > 0:
            fan_energy_output_path = os.path.join(OUTPUT_DIR, f'cooling_tower_{tower_id}_fan_energy_training.csv')
            fan_energy_data[tower_key].to_csv(fan_energy_output_path, index=False, encoding='utf-8-sig')
            logger.info(f"冷却塔{tower_id}风机能耗训练数据已保存到: {fan_energy_output_path}")
    
    # 数据统计信息
    logger.info("\n=== 冷却塔数据处理完成 ===")
    for tower_id in range(1, 5):
        tower_key = f'tower_{tower_id}'
        if tower_key in cooling_tower_data:
            data_shape = cooling_tower_data[tower_key].shape
            logger.info(f"冷却塔{tower_id}原始数据形状: {data_shape}")
            
            if tower_key in heat_transfer_data:
                heat_shape = heat_transfer_data[tower_key].shape
                logger.info(f"冷却塔{tower_id}换热性能数据形状: {heat_shape}")
            
            if tower_key in fan_energy_data:
                fan_shape = fan_energy_data[tower_key].shape
                logger.info(f"冷却塔{tower_id}风机能耗数据形状: {fan_shape}")
            
            # 统计运行时间
            if len(cooling_tower_data[tower_key]) > 0:
                avg_frequency = cooling_tower_data[tower_key]['frequency'].mean()
                max_frequency = cooling_tower_data[tower_key]['frequency'].max()
                logger.info(f"冷却塔{tower_id}平均频率: {avg_frequency:.1f} Hz, 最大频率: {max_frequency:.1f} Hz")
    
    # 返回三种数据集
    return {
        'original_data': cooling_tower_data,
        'heat_transfer_data': heat_transfer_data,
        'fan_energy_data': fan_energy_data
    }
'''
def read_data_for_device_CoolingTower(start_time,end_time):
    '''
    冷却塔数据处理函数--通用模板方案
    '''
    id = 3
        # 使用模糊匹配模式，匹配冷却塔相关字段
    pattern_map = {
        r'1#冷却塔.*频率.*': 'frequency_tower1',
        r'2#冷却塔.*频率.*': 'frequency_tower2', 
        r'3#冷却塔.*频率.*': 'frequency_tower3',
        r'4#冷却塔.*频率.*': 'frequency_tower4',
        r'冷却.*热量表.*流量.*': 'flow_total',
        r'冷却.*热量表.*回水温度.*': 'temp_return',
        r'冷却.*热量表.*出水温度.*': 'temp_supply',
        r'冷却.*热量表.*热量.*': 'heat_total',
        r'1#冷却塔.*功率.*': 'power_tower1',
        r'2#冷却塔.*功率.*': 'power_tower2',
        r'3#冷却塔.*功率.*': 'power_tower3',
        r'4#冷却塔.*功率.*': 'power_tower4',
        #r'冷源-湿球温度': 'wet_bulb_temp',
        #r'冷源-焓值': 'enthalpy'
    }
    
    # 精确匹配的映射
    exact_rename_map = {
        '冷源-湿球温度 (℃)': 'wet_bulb_temp',
        '冷源-焓值 (kJ/kg)': 'enthalpy',
        "时间": "timestamp"
    }
    # 使用模糊搜索函数获取数据
    data_cooling_tower = get_flow_report_with_fuzzy_rename(
        id=id, 
        start_time=start_time, 
        end_time=end_time, 
        pattern_map=pattern_map,
        exact_rename_map=exact_rename_map
    )
    # 数据验证和异常处理
    logger.info(f"获取到的冷却塔原始数据形状: {data_cooling_tower.shape}")
    logger.info(f"获取到的数据列: {data_cooling_tower.columns.tolist()}")
    
    # 检查必要字段是否存在
    required_fields = ['timestamp', 'flow_total', 'temp_return', 'temp_supply', 'heat_total',
                       'wet_bulb_temp', 'enthalpy']
    tower_fields = [f'frequency_tower{i}' for i in range(1, 5)] + [f'power_tower{i}' for i in range(1, 5)]
    missing_fields = []
    for field in required_fields + tower_fields:
        if field not in data_cooling_tower.columns:
            missing_fields.append(field)
    
    if missing_fields:
        logger.warning(f"缺失字段: {missing_fields}")
        # 为缺失的字段填充默认值
        for field in missing_fields:
            if 'frequency' in field:
                data_cooling_tower[field] = 0
            else:
                data_cooling_tower[field] = np.nan
    # 确保timestamp列为datetime类型
    if isinstance(data_cooling_tower['timestamp'].iloc[0], str):
        data_cooling_tower['timestamp'] = pd.to_datetime(data_cooling_tower['timestamp'])
    
    # 数据预处理：处理异常值和缺失值
    original_count = len(data_cooling_tower)
    logger.info(f"原始数据记录数: {original_count}")
    # 数据筛选条件
    filter_conditions = (
        (data_cooling_tower['temp_return'] >= 0) & (data_cooling_tower['temp_return'] <= 50) &
        (data_cooling_tower['temp_supply'] >= 0) & (data_cooling_tower['temp_supply'] <= 50) &
        (data_cooling_tower['flow_total'] >= 10) & (data_cooling_tower['flow_total'] <= 1000) &
        (data_cooling_tower['heat_total'] >= 0) & (data_cooling_tower['heat_total'] <= 100000) &
        (data_cooling_tower['wet_bulb_temp'] >= -10) & (data_cooling_tower['wet_bulb_temp'] <= 50) &
        (data_cooling_tower['frequency_tower1'] >= 0) & (data_cooling_tower['frequency_tower1'] <= 60) &
        (data_cooling_tower['frequency_tower2'] >= 0) & (data_cooling_tower['frequency_tower2'] <= 60) &
        (data_cooling_tower['frequency_tower3'] >= 0) & (data_cooling_tower['frequency_tower3'] <= 60) &
        (data_cooling_tower['frequency_tower4'] >= 0) & (data_cooling_tower['frequency_tower4'] <= 60) &
        (data_cooling_tower['power_tower1'] >= 0) & (data_cooling_tower['power_tower1'] <= 50) &
        (data_cooling_tower['power_tower2'] >= 0) & (data_cooling_tower['power_tower2'] <= 50) &
        (data_cooling_tower['power_tower3'] >= 0) & (data_cooling_tower['power_tower3'] <= 50) &
        (data_cooling_tower['power_tower4'] >= 0) & (data_cooling_tower['power_tower4'] <= 50)
    )
    data_cooling_tower = data_cooling_tower[filter_conditions]
    filtered_count = len(data_cooling_tower)
    logger.info(f"数据筛选完成，保留 {filtered_count}/{original_count} 条记录")
    
    # 去除重复数据
    data_cooling_tower = remove_duplicate_rows(data_cooling_tower, window_size=5)
    deduplicated_count = len(data_cooling_tower)
    logger.info(f"去重完成，保留 {deduplicated_count} 条记录")
    
    # 保存原始处理后的数据
    raw_output_path = os.path.join(OUTPUT_DIR, 'load_data_CoolingTower_raw.csv')
    data_cooling_tower.to_csv(raw_output_path, index=False, encoding='utf-8-sig')
    logger.info(f"原始数据已保存到: {raw_output_path}")

    logger.info("开始进行换热量分配和流量分配计算...")
    # 为每个冷却塔初始化分配的换热量列
    for tower_id in range(1, 5):
        data_cooling_tower[f'allocated_heat_tower{tower_id}'] = 0.0
    
    # 遍历每一行数据，判断是否为有效数据并分配换热量
    for idx in data_cooling_tower.index:
        # 获取当前时刻所有冷却塔的频率
        freq_values = [
            data_cooling_tower.loc[idx, 'frequency_tower1'],
            data_cooling_tower.loc[idx, 'frequency_tower2'],
            data_cooling_tower.loc[idx, 'frequency_tower3'],
            data_cooling_tower.loc[idx, 'frequency_tower4']
        ]
        
        # 筛选出开启的冷却塔（频率大于25Hz）
        running_freqs = [f for f in freq_values if f > 25.0]
        running_tower_ids = [i+1 for i, f in enumerate(freq_values) if f > 25.0]
        
        # 判断是否为有效数据：开启冷却塔数量大于1且频率差值小于2Hz
        if len(running_freqs) >= 1:
            max_freq = max(running_freqs)
            min_freq = min(running_freqs)
            freq_diff = max_freq - min_freq
            
            # 有效数据：频率差值小于2Hz
            if freq_diff <= 5.0:
                # 获取总换热量
                total_heat = data_cooling_tower.loc[idx, 'heat_total']
                total_flow = data_cooling_tower.loc[idx, 'flow_total']
                # 为运行中的冷却塔平分总换热量
                if total_heat > 0:
                    allocated_heat_per_tower = total_heat / len(running_freqs)
                    for tower_id in running_tower_ids:
                        data_cooling_tower.loc[idx, f'allocated_heat_tower{tower_id}'] = allocated_heat_per_tower

                # 为运行中的冷却塔平分总流量
                if total_flow > 0:
                    allocated_flow_per_tower = total_flow / len(running_freqs)
                    for tower_id in running_tower_ids:
                        data_cooling_tower.loc[idx, f'allocated_flow_tower{tower_id}'] = allocated_flow_per_tower


    logger.info("换热量分配和流量分配计算完成")
    
    # 为每个冷却塔分配流量和功耗
    cooling_tower_data = {}

    for tower_id in range(1, 5):
        logger.info(f"处理冷却塔{tower_id}数据...")
        
        # 创建单个冷却塔的数据框
        tower_data = data_cooling_tower[['timestamp', 'temp_return', 'temp_supply', 
                                       'wet_bulb_temp', 'enthalpy', 
                                       f'frequency_tower{tower_id}', f'allocated_heat_tower{tower_id}',
                                       f'allocated_flow_tower{tower_id}',
                                       f'power_tower{tower_id}']
                                       ].copy()
        
        # 重命名列
        tower_data = tower_data.rename(columns={
            f'frequency_tower{tower_id}': 'frequency',
            'temp_return': 'cooling_return_temp',
            'temp_supply': 'cooling_supply_temp',
            f'allocated_flow_tower{tower_id}': 'flow',
            f'power_tower{tower_id}': 'power',
            f'allocated_heat_tower{tower_id}': 'allocated_heat',
        })
        # 选择最终需要的字段
        final_columns = ['timestamp', 'flow', 'frequency', 'power', 
                        'cooling_supply_temp', 'cooling_return_temp', 
                        'wet_bulb_temp', 'enthalpy', 'allocated_heat']
        
        tower_data_final = tower_data[final_columns].copy()
        # 去除缺失值
        tower_data_final = tower_data_final.dropna()
        # 筛选有效运行数据（频率大于0）
        tower_data_final = tower_data_final[tower_data_final['frequency'] >= 25]
        
        logger.info(f"冷却塔{tower_id}有效数据点数: {len(tower_data_final)}")
        
        # 保存单个冷却塔数据
        tower_output_path = os.path.join(OUTPUT_DIR, f'cooling_tower_{tower_id}_data.csv')
        tower_data_final.to_csv(tower_output_path, index=False, encoding='utf-8-sig')
        logger.info(f"冷却塔{tower_id}数据已保存到: {tower_output_path}")
        
        # 存储到结果字典
        cooling_tower_data[f'tower_{tower_id}'] = tower_data_final
    
    # 生成两种不同的训练数据集
    logger.info("\n=== 生成专用训练数据集 ===")
    # 1. 换热性能模型训练数据集
    heat_transfer_data = {}
    fan_energy_data = {}
    
    for tower_id in range(1, 5):
        tower_key = f'tower_{tower_id}'
        if tower_key in cooling_tower_data and len(cooling_tower_data[tower_key]) > 0:
            tower_data = cooling_tower_data[tower_key].copy()
            
            # 换热性能模型数据集 - 关注换热效果
            # 计算温差 (供水温度-湿球温度)
            tower_data['temp_diff'] = tower_data['cooling_supply_temp'] - tower_data['wet_bulb_temp']
            
            # 计算焓差 (使用供水温度和100%相对湿度计算的焓值 - 原焓值)
            tower_data['enthalpy_supply_100rh'] = calc_air_enthalpy_by_t_rh(
                tower_data['cooling_supply_temp'], 100.0
            )
            tower_data['enthalpy_diff'] = tower_data['enthalpy_supply_100rh'] - tower_data['enthalpy']
            
            # 换热量分配逻辑已在数据拆分前完成，这里直接使用预分配的换热量
            
            # 计算换热量 (kW) - 仅使用分配的换热量
            # 只有当allocated_heat存在且大于0时才保留数据，否则设为NaN
            tower_data['heat_transfer_rate'] = np.where(
                (tower_data['allocated_heat'].notna()) & (tower_data['allocated_heat'] > 0),
                tower_data['allocated_heat'],
                np.nan
            )
            
            # 记录换热量计算方式的统计信息
            valid_count = ((tower_data['allocated_heat'].notna()) & (tower_data['allocated_heat'] > 0)).sum()
            invalid_count = len(tower_data) - valid_count
            logger.info(f"冷却塔{tower_id}: 有效分配换热量 {valid_count} 行，无效数据 {invalid_count} 行")
            
            # 过滤掉无效数据（换热量为NaN的行）
            tower_data = tower_data.dropna(subset=['heat_transfer_rate'])
            logger.info(f"冷却塔{tower_id}: 过滤后剩余 {len(tower_data)} 行有效数据")
            
            # 换热性能模型所需字段
            heat_transfer_final_columns = [
                'timestamp', 'flow', 'temp_diff', 'enthalpy_diff', 
                'frequency', 'heat_transfer_rate'
            ]
            
            heat_transfer_tower_data = tower_data[heat_transfer_final_columns].copy()
            
            # 风机能耗模型数据集 - 关注能耗与运行参数关系
            # 风机能耗模型所需字段
            fan_energy_final_columns = [
                'timestamp', 'frequency', 'power'
            ]
            
            fan_energy_tower_data = tower_data[fan_energy_final_columns].copy()
            
            # 数据质量检查和清理
            # 换热性能数据清理
            heat_transfer_tower_data = heat_transfer_tower_data.dropna()
            heat_transfer_tower_data = heat_transfer_tower_data[
                (heat_transfer_tower_data['heat_transfer_rate'] >= 0) &
                (heat_transfer_tower_data['flow'] > 0) &
                (heat_transfer_tower_data['frequency'] > 0)
            ]
            
            # 风机能耗数据清理
            fan_energy_tower_data = fan_energy_tower_data.dropna()
            fan_energy_tower_data = fan_energy_tower_data[
                (fan_energy_tower_data['power'] >= 0) &
                (fan_energy_tower_data['frequency'] > 0)
            ]
            
            # 存储到结果字典
            heat_transfer_data[tower_key] = heat_transfer_tower_data
            fan_energy_data[tower_key] = fan_energy_tower_data
            
            logger.info(f"冷却塔{tower_id}换热性能数据点数: {len(heat_transfer_tower_data)}")
            logger.info(f"冷却塔{tower_id}风机能耗数据点数: {len(fan_energy_tower_data)}")
    
    # 保存换热性能模型训练数据
    logger.info("\n=== 保存换热性能模型训练数据 ===")
    for tower_id in range(1, 5):
        tower_key = f'tower_{tower_id}'
        if tower_key in heat_transfer_data and len(heat_transfer_data[tower_key]) > 0:
            heat_transfer_output_path = os.path.join(OUTPUT_DIR, f'cooling_tower_{tower_id}_heat_transfer_training.csv')
            heat_transfer_data[tower_key].to_csv(heat_transfer_output_path, index=False, encoding='utf-8-sig')
            logger.info(f"冷却塔{tower_id}换热性能训练数据已保存到: {heat_transfer_output_path}")
    
    # 保存风机能耗模型训练数据
    logger.info("\n=== 保存风机能耗模型训练数据 ===")
    for tower_id in range(1, 5):
        tower_key = f'tower_{tower_id}'
        if tower_key in fan_energy_data and len(fan_energy_data[tower_key]) > 0:
            fan_energy_output_path = os.path.join(OUTPUT_DIR, f'cooling_tower_{tower_id}_fan_energy_training.csv')
            fan_energy_data[tower_key].to_csv(fan_energy_output_path, index=False, encoding='utf-8-sig')
            logger.info(f"冷却塔{tower_id}风机能耗训练数据已保存到: {fan_energy_output_path}")
    
    # 数据统计信息
    logger.info("\n=== 冷却塔数据处理完成 ===")
    for tower_id in range(1, 5):
        tower_key = f'tower_{tower_id}'
        if tower_key in cooling_tower_data:
            data_shape = cooling_tower_data[tower_key].shape
            logger.info(f"冷却塔{tower_id}原始数据形状: {data_shape}")
            
            if tower_key in heat_transfer_data:
                heat_shape = heat_transfer_data[tower_key].shape
                logger.info(f"冷却塔{tower_id}换热性能数据形状: {heat_shape}")
            
            if tower_key in fan_energy_data:
                fan_shape = fan_energy_data[tower_key].shape
                logger.info(f"冷却塔{tower_id}风机能耗数据形状: {fan_shape}")
            
            # 统计运行时间
            if len(cooling_tower_data[tower_key]) > 0:
                avg_frequency = cooling_tower_data[tower_key]['frequency'].mean()
                max_frequency = cooling_tower_data[tower_key]['frequency'].max()
                logger.info(f"冷却塔{tower_id}平均频率: {avg_frequency:.1f} Hz, 最大频率: {max_frequency:.1f} Hz")
    
    # 返回三种数据集
    return {
        'original_data': cooling_tower_data,
        'heat_transfer_data': heat_transfer_data,
        'fan_energy_data': fan_energy_data
    }

# 计算换热器的数据
def read_data_for_device_HeatExchanger(start_time,end_time,design_params_heat = None):
    '''
    换热器数据处理函数
    '''
    id = 15
    if design_params_heat == None:
        logger.warning("design_params_heat is None, use default design_params_heat")
        design_params_heat = {"m_a_des": 50000, # m3/h
                           "freq_des": 50}

    rename_map = {"流量": "flow",# 流量
                   "回风湿度 (%)": "RH_hf",# 回风相对湿度
                   "回风温度 (℃)": "t_hf", # 回风温度
                   "LD-A2-出口温度 (℃)": "t_LD_out",# 出口温度
                   "LD-A2-入口温度 (℃)": "t_LD_in",# 入口温度
                   "oriTs":"timestamp",
                    "KT-A1-运行状态": "kt_a1_function",
                    "KT-A1-频率反馈 (Hz)": "kt_a1_freq",
                    "KT-A1-实时功率 (kW)": "kt_a1_power",
                    "KT-A2-频率反馈 (Hz)": "kt_a2_freq",
                    "KT-A2-实时功率 (kW)": "kt_a2_power",
                    "KT-A2-运行状态": "kt_a2_function",
                    "送风湿度 (%)": "supply_air_rh",
                    "送风温度 (℃)": "supply_air_temp",
                    "K-A1-电机转速 (Hz)": "ka1_motor_rpm",
                    "K-A1-功率 (kW)": "ka1_power",
                    "K-A3-电机转速 (Hz)": "ka3_motor_rpm",
                    "K-A3-功率 (kW)": "ka3_power",
                    "K-A2-电机转速 (Hz)": "ka2_motor_rpm",
                    "K-A2-功率 (kW)": "ka2_power",
                    "出水温度 (℃)": "outlet_water_temp",
                    "回水温度 (℃)": "return_water_temp"
                   }
    data_HeatExchanger = get_flow_report(id=id, start_time=start_time, end_time=end_time, rename_map=rename_map)

    # A端综合回风湿球温度计算
    id = 20
    
    # 使用模糊匹配模式，支持不同编号的传感器
    pattern_map = {
        r'ThX[A-Z]\d+HhX[A-Z]\d+-湿度.*': 'RH_hx_1',  # 湿度传感器
        r'ThX[A-Z]\d+HhX[A-Z]\d+-温度实际值.*': 't_hx_1',  # 温度传感器
    }
    
    # 精确匹配的映射
    exact_rename_map = {
        "oriTs": "timestamp"
    }
    # 使用新的模糊搜索函数获取数据
    data_hf = get_flow_report_with_fuzzy_rename(
        id=id, 
        start_time=start_time, 
        end_time=end_time, 
        pattern_map=pattern_map,
        exact_rename_map=exact_rename_map
    )

    # 计算湿球温度
    for i in range(1,4):
        data_hf[f"t_hx_{i}_wetbulb"] = calc_wet_bulb_temperature(
            data_hf[f"t_hx_{i}"], data_hf[f"RH_hx_{i}"]
        )
    # 将data_hf合并到data_HeatExchanger
    data_HeatExchanger = pd.merge(data_HeatExchanger, data_hf, on="timestamp", how="left")



    # 打印所有列名，确认功率列的真实名称
    logger.info("所有列名：%s",data_HeatExchanger.columns.tolist())
    logger.info(data_HeatExchanger.columns.tolist())
    
    power_cols = ["kt_a1_power", "kt_a2_power"]
    # 只保留所有功率都大于0的行
    data_HeatExchanger = data_HeatExchanger[(data_HeatExchanger[power_cols] > 0).all(axis=1)]
    # 只保留流量大于0的行
    data_HeatExchanger = data_HeatExchanger[data_HeatExchanger["flow"] > 0]
    # 只保留频率在20到50的行
    data_HeatExchanger = data_HeatExchanger[(data_HeatExchanger["kt_a1_freq"] >= 20) & (data_HeatExchanger["kt_a1_freq"] <= 50)]


    # 计算回风焓值、湿球温度
    data_HeatExchanger["hf_enthalpy"] = calc_air_enthalpy_by_t_rh(
        data_HeatExchanger["t_hf"], data_HeatExchanger["RH_hf"]
    )
    data_HeatExchanger["hf_wetbulb"] = calc_wet_bulb_temperature(
        data_HeatExchanger["t_hf"], data_HeatExchanger["RH_hf"]
    )
    # 计算送风焓值
    data_HeatExchanger["supply_enthalpy"] = calc_air_enthalpy_by_t_rh(
        data_HeatExchanger["supply_air_temp"], data_HeatExchanger["supply_air_rh"]
    )
    # 计算KT-A1的换热量
    data_HeatExchanger["kt_a1_heat"] = (data_HeatExchanger["hf_enthalpy"] - data_HeatExchanger["supply_enthalpy"])\
         * (data_HeatExchanger["kt_a1_freq"]/design_params_heat["freq_des"]*\
            design_params_heat["m_a_des"]/3600*midu_air)
    # 计算KT-A1的流量
    data_HeatExchanger["kt_a1_flow"] = data_HeatExchanger["flow"]*30/75

    # 总冷量
    data_HeatExchanger["heat_load"] = data_HeatExchanger["flow"] *midu_water*\
            c_water*(data_HeatExchanger['return_water_temp']-data_HeatExchanger['outlet_water_temp'])/3600
    # 总的风机运行频率(根据各个设备的额定风量进行加权平均)
    data_HeatExchanger["freq_all"] = (data_HeatExchanger["kt_a1_freq"]/50*50000 + data_HeatExchanger["kt_a2_freq"]/50*14500 +\
        data_HeatExchanger["ka1_motor_rpm"]/2900*45000 + data_HeatExchanger["ka2_motor_rpm"]/2900*40000 +\
            data_HeatExchanger["ka3_motor_rpm"]/2900*15000)/(50000+14500+45000+40000+15000) *50
    # 总的回风湿球温度
    data_HeatExchanger["t_hf_wetbulb"] = (data_HeatExchanger["t_hx_1_wetbulb"] *data_HeatExchanger["ka1_motor_rpm"]/2900*45000\
                                        + data_HeatExchanger["t_hx_2_wetbulb"] *data_HeatExchanger["ka2_motor_rpm"]/2900*40000\
                                        + data_HeatExchanger["t_hx_3_wetbulb"] *data_HeatExchanger["ka3_motor_rpm"]/2900*15000\
                                        + data_HeatExchanger["hf_wetbulb"] *data_HeatExchanger["kt_a1_freq"]/50*50000\
                                        + data_HeatExchanger["hf_wetbulb"] *data_HeatExchanger["kt_a2_freq"]/50*14500)\
                                        /(data_HeatExchanger["ka1_motor_rpm"]/1450*45000+\
                                          data_HeatExchanger["ka2_motor_rpm"]/1450*40000+\
                                          data_HeatExchanger["ka3_motor_rpm"]/1450*15000+\
                                          data_HeatExchanger["kt_a1_freq"]/50*50000+\
                                          data_HeatExchanger["kt_a2_freq"]/50*14500)
    
    # 筛选数据
    #data_HeatExchanger = data_HeatExchanger[(data_HeatExchanger["heat_load"] >= 100)]

    # 大系统的综合频率
    data_HeatExchanger["freq_kt"] = (data_HeatExchanger["kt_a1_freq"]/50*50000 + data_HeatExchanger["kt_a2_freq"]/50*14500)/(50000+14500) *50
    # 
    data_HeatExchanger["heat_kt"] = (data_HeatExchanger["hf_enthalpy"] - data_HeatExchanger["supply_enthalpy"])\
         * ((data_HeatExchanger["kt_a1_freq"]/50*50000 + data_HeatExchanger["kt_a2_freq"]/50*14500)/(50000+14500)/3600*midu_air)


    # 保存处理后的数据
    data_HeatExchanger.to_csv(os.path.join(OUTPUT_DIR, "HeatExchanger_data_raw.csv"), index=False)
    logger.info(f"原始数据处理完成，保存路径：{os.path.join(OUTPUT_DIR, 'HeatExchanger_data_raw.csv')}")
    # 重命名
    rename_dict = {
        "kt_a1_freq": 'freq',
        #"freq_all":'freq',
        #"freq_kt":'freq',
        "kt_a1_flow":'m_chw',
        #"flow":'m_chw',
        "hf_wetbulb": 't_s_ai',
        #"t_hf_wetbulb":'t_s_ai',
        #"t_hf_wetbulb":'t_s_ai',
        "outlet_water_temp":"t_wi", 
        "kt_a1_heat":'Q_true',
        #"heat_load":'Q_true',
        #"heat_kt":'Q_true',
    }
    data_HeatExchanger_processed = data_HeatExchanger.copy()
    data_HeatExchanger_processed.rename(columns=rename_dict, inplace=True)

    # 需要的列
    columns_needed = ["timestamp", "freq", "m_chw","t_s_ai","t_wi","Q_true"]
    data_HeatExchanger_processed = data_HeatExchanger_processed[columns_needed]
    # 删除nan
    data_HeatExchanger_processed = data_HeatExchanger_processed.dropna()
    # 筛选数据
    data_HeatExchanger_processed = data_HeatExchanger_processed[data_HeatExchanger_processed["Q_true"] > 50]


    logger.info("换热模型数据处理后的信息：")
    logger.info(data_HeatExchanger_processed.head())
    logger.info(data_HeatExchanger_processed.isnull().sum())  # 检查每一列的 NaN 数量
    numeric_cols = data_HeatExchanger_processed.select_dtypes(include=[np.number]).columns
    logger.info(np.isinf(data_HeatExchanger_processed[numeric_cols]).sum()) # 检查每一列的 Inf 数量
    logger.info(data_HeatExchanger_processed.describe())      # 查看数据分布

    # 保存处理后的数据
    data_HeatExchanger_processed.to_csv(os.path.join(OUTPUT_DIR, "HeatExchanger_data_processed.csv"), index=False)
    logger.info(f"数据处理完成，保存路径：{os.path.join(OUTPUT_DIR, 'HeatExchanger_data_processed.csv')}")

    columns_needed_fan = ["timestamp", "kt_a1_power", "kt_a1_freq"]
    data_HeatExchanger_fan = data_HeatExchanger[columns_needed_fan].copy()
    # 删除nan
    data_HeatExchanger_fan = data_HeatExchanger_fan.dropna()
    # 筛选条件："KT-A1-功率"大于0的行
    data_HeatExchanger_fan = data_HeatExchanger_fan[data_HeatExchanger_fan["kt_a1_power"] > 0]
    # 筛选条件："KT-A1-频率"大于0且小于60的行
    data_HeatExchanger_fan = data_HeatExchanger_fan[
        (data_HeatExchanger_fan["kt_a1_freq"] > 0) & (data_HeatExchanger_fan["kt_a1_freq"] < 60)
    ]
    # 重命名
    rename_dict = {
        'kt_a1_power': 'power',
        'kt_a1_freq': 'freq'
    }
    data_HeatExchanger_fan.rename(columns=rename_dict, inplace=True)

    logger.info("风机模型数据处理后的信息：")
    logger.info(data_HeatExchanger_fan.head())
    logger.info(data_HeatExchanger_fan.isnull().sum())  # 检查每一列的 NaN 数量
    numeric_cols = data_HeatExchanger_fan.select_dtypes(include=[np.number]).columns
    logger.info(np.isinf(data_HeatExchanger_fan[numeric_cols]).sum()) # 检查每一列的 Inf 数量
    logger.info(data_HeatExchanger_fan.describe())      # 查看数据分布

    if isinstance(data_HeatExchanger_fan['timestamp'].iloc[0], str):
        data_HeatExchanger_fan['timestamp'] = pd.to_datetime(data_HeatExchanger_fan['timestamp'])
    data_HeatExchanger_fan = data_HeatExchanger_fan[
        ~(
            (data_HeatExchanger_fan['timestamp'] > datetime.datetime(2025, 7, 1))
            &
            (data_HeatExchanger_fan['timestamp'] < datetime.datetime(2025, 7, 15))
        )
    ]

    if isinstance(data_HeatExchanger_processed['timestamp'].iloc[0], str):
        data_HeatExchanger_processed['timestamp'] = pd.to_datetime(data_HeatExchanger_processed['timestamp'])
    data_HeatExchanger_processed = data_HeatExchanger_processed[
        ~(
            (data_HeatExchanger_processed['timestamp'] > datetime.datetime(2025, 7, 1))
            &
            (data_HeatExchanger_processed['timestamp'] < datetime.datetime(2025, 7, 15))
        )
    ]

    # 去除重复行
    logger.info("开始对换热器主数据进行去重处理...")
    data_HeatExchanger_processed = remove_duplicate_rows(data_HeatExchanger_processed, window_size=5)
    
    logger.info("开始对换热器风机数据进行去重处理...")
    data_HeatExchanger_fan = remove_duplicate_rows(data_HeatExchanger_fan, window_size=5)

    # 保存处理后的数据
    data_HeatExchanger_fan.to_csv(os.path.join(OUTPUT_DIR, "HeatExchanger_data_fan.csv"), index=False)
    logger.info(f"数据处理完成，保存路径：{os.path.join(OUTPUT_DIR, 'HeatExchanger_data_fan.csv')}")

    return data_HeatExchanger_processed,data_HeatExchanger_fan


def test_main():
    # 获取当前时间，并将分钟调整为10的倍数，秒为00
    now = datetime.datetime.now()
    # 分钟向下取整到10的倍数
    minute = (now.minute // 10) * 10
    end_time = now.replace(minute=minute, second=0, microsecond=0)
    start_time = end_time - datetime.timedelta(days=10)

    # 格式化为字符串
    start_time_str = start_time.strftime("%Y-%m-%d %H:%M:%S")
    end_time_str = end_time.strftime("%Y-%m-%d %H:%M:%S")

    print(f"测试时间段: {start_time_str} ~ {end_time_str}")

    print("测试冷水机组数据读取...")
    data_refri = read_data_for_device_RefriCycle(start_time_str, end_time_str)
    print(data_refri.head())

    print("测试水泵数据读取...")
    data_pump_flow, data_pump_power = read_data_for_device_ChilledPump(start_time_str, end_time_str)
    print("水泵流量数据：")
    print(data_pump_flow.head())
    print("水泵功率数据：")
    print(data_pump_power.head())

    print("测试换热器数据读取...")
    design_params_heat = {"m_a_des": 50000, "freq_des": 50}
    data_hex, data_hex_fan = read_data_for_device_HeatExchanger(start_time_str, end_time_str, design_params_heat)
    print("换热器主数据：")
    print(data_hex.head())
    print("换热器风机数据：")
    print(data_hex_fan.head())

    return


if __name__ == "__main__":
    # 测试湿球温度计算函数
    # 设计参数
    '''
    # ========== 新增：冷水机组模型拟合示例 ==========
    design_params_lszj = {
        'P_des': 190.7,  # 满载功率 (kW)
        'delta_t_des': 17,  # 满载温差 (℃)
        'Q_des': 930   # 满载负载 (kW)
    }
    from BasicModules.refrigerationCycle_model import RefriCycleModel
    # 初始化模型
    chiller = RefriCycleModel(design_params=design_params_lszj)
    # 读取数据
    data_RefriCycle_1 = read_data_for_device_RefriCycle(start_time="2025-06-01 00:00:00", end_time="2025-06-25 01:00:00")
    # 处理数据
    data = chiller.process_input_data_lsjz(
        wet_bulb_temp=data_RefriCycle_1["t_w_wet"],
        chilled_water_out_temp=data_RefriCycle_1["t_LD_out"],
        Q=data_RefriCycle_1["load"],
        P=data_RefriCycle_1["power"]
    )
    # 转成DataFrame
    data_df = pd.DataFrame(data, columns=['delta_t_bar', 'Q_bar', 'P_bar'])
    data_df.to_csv(os.path.join(OUTPUT_DIR, "load_data_RefriCycle_1_processed.csv"), index=False)
    print(data_df.isnull().sum())  # 检查每一列的 NaN 数量
    print(np.isinf(data_df).sum()) # 检查每一列的 Inf 数量
    print(data_df.describe())      # 查看数据分布
    
    # 拟合
    chiller.fit_coefficients(data=data)
    metrics = chiller.validate(data=data)
    print(metrics)

    # ========== 新增：水泵流量模型与功率模型拟合示例 ==========
    # 设计参数
    design_params_pump = {
        'design_freq': 50.0,    # 设计频率 (Hz)
        'design_power': 18.9,    # 设计功率 (kW)
        'design_flow': 176,    # 设计流量 (m³/h)
        'min_freq': 35.0,       # 最小频率 (Hz)
        'max_freq': 50.0        # 最大频率 (Hz)
    }
    from BasicModules.pump_model import PumpModel
    # 初始化模型
    pump = PumpModel(design_params=design_params_pump)
    # 读取数据
    data_flow_group, data_power_group = read_data_for_device_Pump(start_time="2025-06-01 00:00:00", end_time="2025-06-10 01:00:00")
    
    # 处理流量模型数据
    flow_data = pump.process_input_data_flow(
        frequency=data_flow_group["frequency"],
        flow=data_flow_group["flow"]
    )
    flow_data_df = pd.DataFrame(flow_data, columns=['freq_bar', 'flow_bar'])
    flow_data_df.to_csv(os.path.join(OUTPUT_DIR, "pump_flow_data_processed.csv"), index=False)
    
    # 处理功率模型数据
    power_data = pump.process_input_data_power(
        frequency=data_power_group["frequency"],
        power=data_power_group["power"]
    )
    power_data_df = pd.DataFrame(power_data, columns=['freq_bar', 'power_bar'])
    power_data_df.to_csv(os.path.join(OUTPUT_DIR, "pump_power_data_processed.csv"), index=False)
    
    # 检查数据质量
    print("流量模型数据质量检查:")
    print(flow_data_df.isnull().sum())
    print(np.isinf(flow_data_df).sum())
    print(flow_data_df.describe())
    
    print("功率模型数据质量检查:")
    print(power_data_df.isnull().sum())
    print(np.isinf(power_data_df).sum())
    print(power_data_df.describe())
    
    def hash_data(data):
        return hashlib.md5(str(data).encode()).hexdigest()

    # 拟合流量模型
    pump.fit_coefficients(data=flow_data, method="flow")
    flow_metrics = pump.validate(data=flow_data, method="flow")
    print(f"流量模型验证指标: {flow_metrics}")
    
    # 拟合功率模型前后打印数据和参数
    print("power_data for fit:", power_data)
    print("fit前数据hash:", hash_data(power_data))
    params = pump.fit_coefficients(data=power_data, method="power")
    print("拟合参数:", params)
    print("fit后参数:", pump.b_coefficients)
    print("power_data for validate:", power_data)
    print("validate前数据hash:", hash_data(power_data))
    print("validate时参数:", pump.b_coefficients)
    power_metrics = pump.validate(data=power_data, method="power")
    print(f"功率模型验证指标: {power_metrics}")
    '''
    '''
    start_time = "2025-06-01 00:00:00"
    end_time = "2025-06-25 01:00:00"

    design_params_heat = {"m_a_des": 50000, # m3/h
                           "freq_des": 50}
    data_HeatExchanger_processed,data_HeatExchanger_fan = read_data_for_device_HeatExchanger(start_time,end_time,design_params_heat)
    print('*'*50)
    # ========== 新增：风机模型与换热器模型拟合示例 ==========
    from BasicModules.fan_model import FanModel
    from BasicModules.surface_type_heat_exchanger_model import SurfaceTypeHeatExchangerModel

    # 1. 风机模型拟合
    fan_design_params = {
        'rated_freq': 50,         # Hz
        'design_power': 22,      # kW
        'design_flow': 50000,       #
        'min_freq': 20,          # Hz
        'max_freq': 50           # Hz
    }
    fan_model = FanModel(design_params=fan_design_params)
    print('*-'*50)
    # 数据拆分和拟合    
    freqs = data_HeatExchanger_fan['freq'].values
    powers = data_HeatExchanger_fan['power'].values
    coeffs = fan_model.fit_coefficients(freqs, powers)
    logger.info(f"风机功率模型拟合系数: {coeffs}")
    metrics = fan_model.validate_power_model(freqs, powers)
    logger.info(f"风机功率模型验证指标: {metrics}")


    # 2. 换热器模型拟合
    hex_design_params = {
        'design_heat_transfer': 345,     # kW
        'design_water_flow': 170,         # 
        'design_air_flow': 50000,           # 
        'design_air_temp': 20,           # ℃
        'design_water_temp': 7          # ℃
    }
    hex_model = SurfaceTypeHeatExchangerModel(design_params=hex_design_params, fan_model=fan_model)
    # 进行拟合
    hex_model.fit_coefficients(data_HeatExchanger_processed)
    '''

    test_main()